package com.doudizu.shoesonline.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.doudizu.shoesonline.common.ErrorCode;
import com.doudizu.shoesonline.common.UserContext;
import com.doudizu.shoesonline.constant.UserConstant;
import com.doudizu.shoesonline.exception.BusinessException;
import com.doudizu.shoesonline.mapper.ProductMapper;
import com.doudizu.shoesonline.model.dto.product.ProductDTO;
import com.doudizu.shoesonline.model.dto.product.ProductQuery;
import com.doudizu.shoesonline.model.entity.*;
import com.doudizu.shoesonline.model.vo.ProductDetailVO;
import com.doudizu.shoesonline.model.vo.ProductVO;
import com.doudizu.shoesonline.service.*;
import com.doudizu.shoesonline.utils.AlgorithmUtils;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
* @author ln
* @description 针对表【product(产品)】的数据库操作Service实现
* @createDate 2023-07-03 09:55:39
*/
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
    implements ProductService{

    @Value("${file.path.picture:}")
    String pictureFolder;

    @Resource
    private LinkService linkService;

    @Resource
    private TypeService typeService;

    @Resource
    private BrandService brandService;

    @Resource
    private UserService userService;

    @Resource
    private ProductColorService productColorService;

    @Resource
    private ProductSizeService productSizeService;

    @Resource
    private ProductMapper productMapper;

    @Resource
    private ColorService colorService;

    @Resource
    private SizeService sizeService;

    @Resource
    private OrdersService ordersService;

    @Resource
    private OrderDetailService orderDetailService;

    @Override
    @Transactional
    public void addProduct(ProductDTO productDTO) {
        if (productDTO==null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"请求参数为空");
        }
        try {
            List<Integer> ids = productDTO.getPicIds();
            Product product = new Product();
            BeanUtil.copyProperties(productDTO,product);
            product.setSales(0);
            List<Link> links = linkService.listByIds(productDTO.getPicIds());
            for (Link link : links) {
                link.setLinkName(productDTO.getProductName() + "的产品图片");
                linkService.saveOrUpdate(link);
            }

            product.setPictureLinkId(String.join(",",ids.stream().map(String::valueOf).collect(Collectors.toList())));
            this.save(product);
            Integer productId = product.getId();
            List<Integer> colorIds = productDTO.getColorIds();
            for (Integer colorId : colorIds) {
                ProductColor productColor = new ProductColor();
                productColor.setProductId(productId);
                productColor.setColorId(colorId);
                productColorService.save(productColor);
            }
            List<Integer> sizeIds = productDTO.getSizeIds();
            for (Integer sizeId : sizeIds) {
                ProductSize productSize = new ProductSize();
                productSize.setProductId(productId);
                productSize.setSizeId(sizeId);
                productSizeService.save(productSize);
            }

        } catch (Exception e) {
            log.error("addProduct异常",e);
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"添加失败");
        }
    }


    @Override
    public ProductVO transferToVO(Product product) {
        ProductVO productVO = new ProductVO();

        BeanUtil.copyProperties(product,productVO);

        String typeName = typeService.getById(product.getTypeId()).getTypeName();
        String brandName = brandService.getById(product.getBrandId()).getBrandName();

        String ids = product.getPictureLinkId();
        String[] idArray = ids.split(",");
        List<Integer> list = Arrays.stream(idArray).map(Integer::valueOf).collect(Collectors.toList());
        List<String> urlList = list.stream().map(item -> linkService.getById(item).getUrl()).collect(Collectors.toList());

        productVO.setTypeId(product.getTypeId());
        productVO.setType(typeName);
        productVO.setBrand(brandName);
        productVO.setPictureLink(urlList);

        return productVO;
    }

    @Override
    @Transactional
    public void updateProduct(ProductDTO productDTO) {
        if (productDTO==null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"请求参数为空");
        }
        Integer id = productDTO.getId();
        try {
            Product product = new Product();
            product.setId(id);
            if (productDTO.getProductName() == null) {
                Product byId = this.getById(id);
                productDTO.setProductName(byId.getProductName());
            }
            BeanUtil.copyProperties(productDTO,product);
            if (productDTO.getPicIds() != null && productDTO.getPicIds().size() > 0) {
                List<Link> links = linkService.listByIds(productDTO.getPicIds());
                for (Link link : links) {
                    link.setLinkName(productDTO.getProductName() + "的产品图片");
                    linkService.saveOrUpdate(link);
                }
                List<Integer> ids = productDTO.getPicIds();
                product.setPictureLinkId(String.join(",",ids.stream().map(String::valueOf).collect(Collectors.toList())));
            }
            this.updateById(product);
            //TODO ???
            List<Integer> colorIds = productDTO.getColorIds();
            if (colorIds != null) {
                for (Integer colorId : colorIds) {
                    QueryWrapper<ProductColor> productColorQueryWrapper = new QueryWrapper<>();
                    productColorQueryWrapper.eq("product_id",id);
                    productColorService.remove(productColorQueryWrapper);
                }
                for (Integer colorId : colorIds) {
                    ProductColor productColor = new ProductColor();
                    productColor.setProductId(id);
                    productColor.setColorId(colorId);
                    productColorService.save(productColor);
                }
            }
            List<Integer> sizeIds = productDTO.getSizeIds();
            if (sizeIds != null) {
                for (Integer sizeId : sizeIds) {
                    QueryWrapper<ProductSize> productSizeQueryWrapper = new QueryWrapper<>();
                    productSizeQueryWrapper.eq("product_id",id);
                    productSizeService.remove(productSizeQueryWrapper);
                }
                for (Integer sizeId : sizeIds) {
                    ProductSize productSize = new ProductSize();
                    productSize.setProductId(id);
                    productSize.setSizeId(sizeId);
                    productSizeService.save(productSize);
                }
            }
        } catch (Exception e) {
            log.error("updateProduct异常",e);
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"修改失败");
        }

    }


    @Override
    public Object condition(ProductQuery productQuery) {
        if (productQuery == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        Integer pageNum = productQuery.getPageNum();
        Integer pageSize = productQuery.getPageSize();
        Integer colorId = productQuery.getColorId();
        Integer sizeId = productQuery.getSizeId();
        Integer id = productQuery.getId();
        Integer typeId = productQuery.getTypeId();
        Integer brandId = productQuery.getBrandId();
        String productName = productQuery.getProductName();
        Integer gender = productQuery.getGender();
        Integer status = productQuery.getStatus();
        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        Long userId = UserContext.getUserId();
        User loginUser = userService.getById(userId);
        if (loginUser == null || !UserConstant.ADMIN_ROLE.equals(loginUser.getRole())) {
            queryWrapper.eq("status", 1);
        }
        queryWrapper.eq(status != null,"status",status);
        queryWrapper.eq(id != null, "id", id);
        queryWrapper.eq(typeId != null, "type_id", typeId);
        queryWrapper.eq(brandId != null, "brand_id", brandId);
        queryWrapper.like(StringUtils.isNotBlank(productName), "product_name", productName);
        queryWrapper.eq(gender != null, "gender", gender);
        if (StringUtils.isNotBlank(productQuery.getBrand())) {
            QueryWrapper<Brand> brandQueryWrapper = new QueryWrapper<>();
            brandQueryWrapper.like("brand_name",productQuery.getBrand());
            List<Brand> brandList = brandService.list(brandQueryWrapper);
            for (Brand brand : brandList) {
                queryWrapper.eq("brand_id",brand.getId());
            }
        }

        Object obj = null;
        List<Product> list = null;
        if (pageNum == null || pageSize == null) {
            list = this.list(queryWrapper);

            if (colorId != null) {
                list = list.stream().filter(product -> {
                    QueryWrapper<ProductColor> productColorQueryWrapper = new QueryWrapper<>();
                    productColorQueryWrapper.eq("color_id",colorId);
                    ProductColor productColor = productColorService.getOne(productColorQueryWrapper);
                    Integer productId = productColor.getProductId();
                    if (productId == product.getId()) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }

            if (sizeId != null) {
                list = list.stream().filter(product -> {
                    QueryWrapper<ProductSize> productSizeQueryWrapper = new QueryWrapper<>();
                    productSizeQueryWrapper.eq("size_id",sizeId);
                    ProductSize productSize = productSizeService.getOne(productSizeQueryWrapper);
                    Integer productId = productSize.getProductId();
                    if (productId == product.getId()) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }

            List<ProductVO> voList = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                ProductVO productVO = this.transferToVO(list.get(i));
                voList.add(i, productVO);
            }

            if (productQuery.getBrand() != null) {
                voList = voList.stream().filter(productVO -> {
                    String brand = productVO.getBrand();
                    if (brand.contains(productQuery.getBrand())) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }

            obj = voList;
        }
        if (pageNum != null && pageSize != null) {
            Page<Product> productPage = new Page<>(pageNum,pageSize);
            Page<Product> page = this.page(productPage, queryWrapper);
            list = page.getRecords();

            if (colorId != null) {
                list = list.stream().filter(product -> {
                    QueryWrapper<ProductColor> productColorQueryWrapper = new QueryWrapper<>();
                    productColorQueryWrapper.eq("color_id",colorId);
                    ProductColor productColor = productColorService.getOne(productColorQueryWrapper);
                    Integer productId = productColor.getProductId();
                    if (productId == product.getId()) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }

            if (sizeId != null) {
                list = list.stream().filter(product -> {
                    QueryWrapper<ProductSize> productSizeQueryWrapper = new QueryWrapper<>();
                    productSizeQueryWrapper.eq("size_id",sizeId);
                    ProductSize productSize = productSizeService.getOne(productSizeQueryWrapper);
                    Integer productId = productSize.getProductId();
                    if (productId == product.getId()) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }

            List<ProductVO> voList = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                ProductVO productVO = this.transferToVO(list.get(i));
                voList.add(i, productVO);
            }
            Page<ProductVO> voPage = new Page<>();
            BeanUtil.copyProperties(page,voPage);

            if (productQuery.getBrand() != null) {
                voList = voList.stream().filter(productVO -> {
                    String brand = productVO.getBrand();
                    if (brand.contains(productQuery.getBrand())) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
            }
            voPage.setRecords(voList);

            obj = voPage;
        }

        return obj;

    }


    @Override
    public ProductDetailVO getProductDetail(Integer id) {
        Product product = productMapper.selectById(id);
        if (product == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"商品不存在");
        }
        ProductDetailVO productDetailVO = new ProductDetailVO();
        BeanUtil.copyProperties(product,productDetailVO);
        String brandName = brandService.getById(product.getBrandId()).getBrandName();
        String typeName = typeService.getById(product.getTypeId()).getTypeName();

        String ids = product.getPictureLinkId();
        String[] idArray = ids.split(",");
        List<Integer> list = Arrays.stream(idArray).map(Integer::valueOf).collect(Collectors.toList());
        List<String> urlList = list.stream().map(item -> linkService.getById(item).getUrl()).collect(Collectors.toList());

        productDetailVO.setBrand(brandName);
        productDetailVO.setBrandId(this.getById(id).getBrandId());
        productDetailVO.setType(typeName);
        productDetailVO.setPictureLink(urlList);

        QueryWrapper<ProductColor> productColorQueryWrapper = new QueryWrapper<>();
        productColorQueryWrapper.eq("product_id",id);
        List<ProductColor> productColorList = productColorService.list(productColorQueryWrapper);

        List<String> colors = productColorList.stream().map(productColor -> {
            Integer colorId = productColor.getColorId();
            Color color = colorService.getById(colorId);
            return color.getColorName();
        }).collect(Collectors.toList());
        List<Integer> colorIds = productColorList.stream().map(productColor -> {
            Integer colorId = productColor.getColorId();
            Color color = colorService.getById(colorId);
            return color.getId();
        }).collect(Collectors.toList());

        QueryWrapper<ProductSize> productSizeQueryWrapper = new QueryWrapper<>();
        productSizeQueryWrapper.eq("product_id",id);
        List<ProductSize> productSizeList = productSizeService.list(productSizeQueryWrapper);
        List<Double> sizes = productSizeList.stream().map(productSize -> {
            Integer sizeId = productSize.getSizeId();
            Size size = sizeService.getById(sizeId);
            return size.getSize();
        }).collect(Collectors.toList());
        List<Integer> sizeIds = productSizeList.stream().map(productSize -> {
            Integer sizeId = productSize.getSizeId();
            Size size = sizeService.getById(sizeId);
            return size.getId();
        }).collect(Collectors.toList());

        productDetailVO.setColor(colors);
        productDetailVO.setColorIds(colorIds);
        productDetailVO.setSize(sizes);
        productDetailVO.setSizeIds(sizeIds);

        return productDetailVO;
    }

    @Override
    public Object recommend(Integer pageNum, Integer pageSize) {
        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("sales");
        Long userId = UserContext.getUserId();
        User loginUser = userService.getById(userId);
        if (loginUser == null || !UserConstant.ADMIN_ROLE.equals(loginUser.getRole())) {
            queryWrapper.eq("status", 1);
        }

        Object obj = null;
        List<Product> list = null;
        if (pageNum == null || pageSize == null) {
            list = this.list(queryWrapper);
            List<ProductVO> voList = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                ProductVO productVO = this.transferToVO(list.get(i));
                voList.add(i, productVO);
            }
            obj = voList;
        }
        if (pageNum != null && pageSize != null) {
            Page<Product> productPage = new Page<>(pageNum,pageSize);
            Page<Product> page = this.page(productPage, queryWrapper);
            list = page.getRecords();

            List<ProductVO> voList = new ArrayList<>(list.size());
            for (int i = 0; i < list.size(); i++) {
                ProductVO productVO = this.transferToVO(list.get(i));
                voList.add(i, productVO);
            }
            Page<ProductVO> voPage = new Page<>();
            BeanUtil.copyProperties(page,voPage);
            voPage.setRecords(voList);
            obj = voPage;
        }

        return obj;
    }

    public Object recommend() {
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            return condition(new ProductQuery());
        }
        QueryWrapper<Orders> ordersQueryWrapper = new QueryWrapper<>();

        ordersQueryWrapper.eq("user_id",loginUser.getId());
        List<OrderDetail> detailList = new ArrayList<>();
        List<Orders> ordersList = ordersService.list(ordersQueryWrapper);
        for (Orders orders : ordersList) {
            Long id = orders.getId();
            QueryWrapper<OrderDetail> orderDetailQueryWrapper = new QueryWrapper<>();
            orderDetailQueryWrapper.eq("order_id",id);
            detailList = orderDetailService.list(orderDetailQueryWrapper);
        }
        List<Integer> productIdList = detailList.stream().map(OrderDetail::getProductId).collect(Collectors.toList());
        List<String> myProductList = productIdList.stream().map(id -> {
            Product product = this.getById(id);
            return product.getProductName();
        }).collect(Collectors.toList());

        List<Product> products = this.list();
        List<String> productList = products.stream().map(Product::getProductName).collect(Collectors.toList());

        // 列表的下标 => 相似度
        List<Pair<Product, Long>> list = new ArrayList<>();

        // 计算分数
        for (int i = 0; i < productList.size(); i++) {
            Product product = products.get(i);
            String productName = product.getProductName();
            for (int j = 0; j < myProductList.size(); j++) {
                long distance = AlgorithmUtils.minDistance(productName, myProductList.get(j));
                list.add(new Pair<>(product, distance));
            }
        }
        // 按编辑距离由小到大排序
        List<Pair<Product, Long>> topPairList = list.stream()
                .sorted((a, b) -> (int) (a.getValue() - b.getValue()))
                .collect(Collectors.toList());
        // 原本顺序的 Id 列表
        List<Integer> newIdList = topPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", newIdList);
        // 1, 3, 2
        // User1、User2、User3
        // 1 => User1, 2 => User2, 3 => User3
        Map<Integer, List<Product>> listMap = this.list(queryWrapper).stream().collect(Collectors.groupingBy(Product::getId));
        List<Product> finalProductList = new ArrayList<>();
        for (Integer id : newIdList) {
            finalProductList.add(listMap.get(id).get(0));
        }
        return finalProductList.stream().map(this::transferToVO).collect(Collectors.toList());
    }

}

